package com.ruoyi.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.workflow.domain.CarPackageAudit;
import com.ruoyi.workflow.domain.ServiceItem;
import com.ruoyi.workflow.mapper.CarPackageAuditMapper;
import com.ruoyi.workflow.mapper.ServiceItemMapper;
import com.ruoyi.workflow.service.IServiceItemService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import static com.ruoyi.workflow.constant.AuditConstant.*;

/**
 * 服务项Service业务层处理
 *
 * @author xiaodu
 * @date 2023-06-29
 */
@Service
public class ServiceItemServiceImpl extends ServiceImpl<ServiceItemMapper,ServiceItem> implements IServiceItemService {
    @Autowired
    private ServiceItemMapper serviceItemMapper;
    @Autowired
    private CarPackageAuditMapper carPackageAuditMapper;
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 查询服务项
     *
     * @param id 服务项主键
     * @return 服务项
     */
    @Override
    public ServiceItem selectServiceItemById(Long id) {
        return serviceItemMapper.selectServiceItemById(id);
    }

    /**
     * 查询服务项列表
     *
     * @param serviceItem 服务项
     * @return 服务项
     */
    @Override
    public List<ServiceItem> selectServiceItemList(ServiceItem serviceItem) {
        return serviceItemMapper.selectServiceItemList(serviceItem);
    }

    /**
     * 新增服务项
     *
     * @param serviceItem 服务项
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertServiceItem(ServiceItem serviceItem) {
        //判断是否是套餐
        //如果是套餐，审核状态调整为 初始化
        if (serviceItem.getCarPackage().equals(SI_CAR_PACKAGE_YES)) {
            serviceItem.setAuditStatus(SI_AUDIT_STATUS_INIT);
        } else {
            //如果不是套餐，审核状态调整为 无需审核
            serviceItem.setAuditStatus(SI_AUDIT_STATUS_NOAUDITREQUIRED);
        }
        //设置服务为未上架
        serviceItem.setSaleStatus(SI_SALE_STATUS_DOWN);
        return serviceItemMapper.insertServiceItem(serviceItem);
    }

    /**
     * 修改服务项
     *
     * @param serviceItem 服务项
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateServiceItem(ServiceItem serviceItem) {
        //1.审核状态为-审核中抛异常
        if (serviceItem.getAuditStatus().equals(SI_AUDIT_STATUS_REVIEW)) {
            throw new ServiceException("非法操作：审核中");
        }
        //2.判断是否是上架，如果是上架不可修改
        if (serviceItem.getSaleStatus().equals(SI_SALE_STATUS_UP)) {
            throw new ServiceException("非法操作：已上架");
        }

        //3.判断是否是套餐
        if (serviceItem.getCarPackage().equals(SI_CAR_PACKAGE_NO)) {
            //3.1.如果不是套餐，要把审核状态改为：无需审核
            serviceItem.setAuditStatus(SI_AUDIT_STATUS_NOAUDITREQUIRED);
        } else {
            //3.2.如果是套餐，要把审核状态改为：初始化
            serviceItem.setAuditStatus(SI_AUDIT_STATUS_INIT);
        }
        //4.更新操作
        return serviceItemMapper.updateServiceItem(serviceItem);
    }

    /**
     * 发起服务套餐审核流程
     * @param id 服务项id
     * @param packageAuditInfo 发起套餐审核的备注信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void startAudit(Long id,String packageAuditInfo) {
        //根据id，查询服务项
        ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(id);
        //1.先判断是否是套餐
        if (serviceItem.getCarPackage().equals(SI_CAR_PACKAGE_NO)) {
            //不是套餐，则抛出异常，非套餐，无需审核
            throw new ServiceException("非套餐,无需审核");
        }
        //2.把审核状态改为：审核中【服务项表和套餐信息表】，并把数据保存到套餐审核表中
        //把审核状态改为审核中 SI_AUDIT_STATUS_REVIEW
        ServiceItem serviceItemChangedObj = new ServiceItem();
        serviceItemChangedObj.setId(serviceItem.getId());
        serviceItemChangedObj.setAuditStatus(SI_AUDIT_STATUS_REVIEW);
        serviceItemMapper.updateServiceItem(serviceItemChangedObj);
        serviceItem.setAuditStatus(SI_AUDIT_STATUS_REVIEW);

        //优化方案：这些信息根据前端传的id，从后端查询出来，防止信息被篡改
        // 把审核的 id,name,info,price,creatorId,creatorUserName,creatorNickName,createTime,status 字段封装到套餐新对象中
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        CarPackageAudit carPackageAudit = new CarPackageAudit(
                serviceItem.getId(),
                serviceItem.getName(),
                serviceItem.getInfo(),
                serviceItem.getDiscountPrice(),
                user.getUserId(),
                user.getUserName(),
                user.getNickName(),
                new Date(),
                packageAuditInfo,
                SI_AUDIT_STATUS_REVIEW
        );
        // 把套餐信息对象插入到套餐信息表中
        carPackageAuditMapper.insertCarPackageAudit(carPackageAudit);
        // 获取保存后的id
        Long businessKey = carPackageAudit.getId();

        //3.启动审核流程实例
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取service
        RuntimeService runtimeService = processEngine.getRuntimeService();
        TaskService taskService = processEngine.getTaskService();

        // 根据流程定义key，启动流程实例，并绑定businessKey
        //设置流程变量
        BigDecimal discountPrice = serviceItem.getDiscountPrice();
        HashMap<String, Object> map = new HashMap<>();
        map.put("money", discountPrice.doubleValue());
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(BUS_CAR_PACKAGE_KEY, String.valueOf(businessKey), map);
        // 启动流程实例后获取流程实例ID
        String processInstanceId = processInstance.getProcessInstanceId();
        //把流程实例保存到审核套餐中
        CarPackageAudit carPackageAuditByDeploymentId = new CarPackageAudit();
        carPackageAuditByDeploymentId.setId(businessKey);
        carPackageAuditByDeploymentId.setInstanceId(processInstanceId);
        carPackageAuditMapper.updateCarPackageAudit(carPackageAuditByDeploymentId);

        //4.设置候选人
        //注意：只能到哪个任务节点，才能为该任务结节点设置候选人
        //获取当前任务节点
        Task currentTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        //根据任务结点的key查询候选人
        List<SysUser> userList = sysUserMapper.selectUserByNodeIdOrKey(null, currentTask.getTaskDefinitionKey());
        //设置候选人设置的是userId,而我们为了解决代码耦合，是通过userName查找用户，我们把userId的值设置成userName
        userList.forEach(item -> taskService.addCandidateUser(currentTask.getId(), item.getUserName()));
    }

    /**
     * 上架/下架服务项
     *
     * @param id         服务项id
     * @param saleStatus 服务项上架状态
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeSaleStatus(Long id, Integer saleStatus) {
        //根据id修改上架状态
        //注意：上架前判断是否是套餐，如果是套餐，是否审核通过，只有审核通过才能上架和下架
        ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(id);
        Integer auditStatus = serviceItem.getAuditStatus();
        //判断是否是套餐
        //如果是套餐，判断审核通过才能修改上架/下架服务项
        //如果不是套餐,并且无需审核
        if ((serviceItem.getCarPackage().equals(SI_CAR_PACKAGE_NO)
                && serviceItem.getAuditStatus().equals(SI_AUDIT_STATUS_NOAUDITREQUIRED))
                ||
                (serviceItem.getCarPackage().equals(SI_CAR_PACKAGE_YES)
                        && auditStatus.equals(SI_AUDIT_STATUS_PASS))) {

            ServiceItem serviceItemUpdateObj = new ServiceItem();
            serviceItemUpdateObj.setId(id);
            serviceItemUpdateObj.setSaleStatus(saleStatus);
            serviceItemMapper.updateServiceItem(serviceItemUpdateObj);
        } else {
            throw new ServiceException("操作违规！！!");
        }
    }

    /**
     * 修改审核列表 -- 服务项
     * @param serviceItem
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateFormServiceItem(ServiceItem serviceItem) {
        //根据id查询服务项信息
        ServiceItem oldObj = this.getById(serviceItem.getId());
        //判断服务项信息的状态是否是 --》 审批拒绝
        //审批拒绝才能修改表单，否则非法操作
        if(!SI_AUDIT_STATUS_OUT.equals(oldObj.getAuditStatus())){
            throw new ServiceException("非法操作!");
        }

        //把拒绝改为 调整申请 SI_AUDIT_STATUS_READJUST
        this.update(new LambdaUpdateWrapper<ServiceItem>()
                .set(ServiceItem::getName,serviceItem.getName())
                .set(ServiceItem::getOriginalPrice,serviceItem.getOriginalPrice())
                .set(ServiceItem::getDiscountPrice,serviceItem.getDiscountPrice())
                .set(ServiceItem::getServiceCatalog,serviceItem.getServiceCatalog())
                .set(ServiceItem::getInfo,serviceItem.getInfo())
                .set(ServiceItem::getAuditStatus,SI_AUDIT_STATUS_READJUST)
                .eq(ServiceItem::getId,serviceItem.getId()));
    }


}
